//
//  parse_nt.h
//  cobalt
//
//  Created by Nicolas Godbout on 2013-08-21.
//  Copyright (c) 2013 Nicolas Godbout. All rights reserved.
//

#ifndef __cobalt__parse_nt__
#define __cobalt__parse_nt__

#include "parse.h"

#include "environment.h"

/**     A parser for the official N-Triples grammar found at
            http://www.w3.org/TR/rdf-testcases/#ntriples

        ...except that it does not yet parse \\ escapes within URI references
 **/

using namespace rdf;

class ParseNT : public Parser {
    Environment*     env;
    Graph            graph;
    Graph            processorGraph;
public:
    ParseNT(Environment* env)
    : Parser()
    , env(env) {
        graph = env->createGraph({});
        processorGraph = env->createGraph({});
        if ( !inited )
            init();
    }
    
    bool parse(const std::string&);
    Graph& getGraph();
    
    template <class T>
    std::list<T> many(T (ParseNT::*)());
    
private:
    bool        ntripleDoc();
    Triple      line();
    void        comment();
    Triple      triple();
    RDFNode     subject();
    RDFNode     predicate();
    RDFNode     object();
    RDFNode     uriref();
    RDFNode     nodeID();
    RDFNode     literal();
    void        manyWS();
    void        someWS();
    
private:
    static void         init();
    static bool         inited;
    static std::regex   re_Comment;
    static std::regex   re_URIRef;
    static std::regex   re_Blank;
    static std::regex   re_String;
    static std::regex   re_Language;
};

inline Graph&
ParseNT::getGraph() {
    return graph;
}

template <class T>
std::list<T>
ParseNT::many(T (ParseNT::* func)()) {
    NOERR
    std::list<T> ret{};
    status = OK_NC;
    while (true) {
        T elem = (this->*func)();
        if (status == OK_NC)
            abort();    // 'many' called with a parser accepting empty input
        else if (status == OK) {
            ret.push_back(elem);
            status = OK_NC;
            continue;
        }
        break;
    }
    if ( ret.empty() )
        status = OK_NC;
    else
        status = OK;
    return ret;
}

#endif /* defined(__cobalt__parse_nt__) */
